import java.io.Reader;
import java.io.IOException;

public class Scanner {//Nuestro analizador l�xico
	private Reader input;//fichero del que lee el programa
	private String lex;
	private int sigCar;
	private int estado;
	private int contFilas;
	private String tablaReservada[];
	
	public Scanner(Reader input) {
		this.input=input;
        lex = new String();
   }
		
	/*Usamos una tabla reservada independiente de la tabla de
	simbolos, donde tendremos palabras reservadas de nuestro lenguaje*/
	
	 public void iniciaTablaReservada(){

        tablaReservada[0] = "natural";
        tablaReservada[1] = "real";
        tablaReservada[2] = "in";
        tablaReservada[3] = "out";
        tablaReservada[4] = "int";
        tablaReservada[5] = "if";
        tablaReservada[6] = "then";
        tablaReservada[7] = "else";
        tablaReservada[8] = "elsif";
        tablaReservada[9] = "fi";
        tablaReservada[10] = "while";
        tablaReservada[11] = "do";
        tablaReservada[12] = "endwhile";
        tablaReservada[13] = "tipo";
        tablaReservada[14] = "rec";
        tablaReservada[15] = "endrec";
        tablaReservada[16] = "pointer";
        tablaReservada[17] = "alloc";
        tablaReservada[18] = "free";
        tablaReservada[19] = "null";
        tablaReservada[20] = "fun";
        tablaReservada[21] = "returns";
        tablaReservada[22] = "return";
        tablaReservada[23] = "end";
        
        
    }
	
	public void inicializa() throws IOException {
	     sigCar =input.read();
	     contFilas = 1;
	     tablaReservada = new String[24];
	     iniciaTablaReservada();
	    }
	
	/*Para la implementaci�n del dameToken(), usamos el aut�mata
	de nuestra memoria. Mismos estados. Implementado como una m�quina de estados.
	Nos devolver� la categor�a del token que le entra, as� como
	su valor exacto(lexema)*/
	
	public String dameToken() throws IOException {
	     estado = 0;
	     lex = "";
	     while(true) {
	         switch(estado) {
	           case 0:{
	        	  if (sigCar == '\n'){ 
	        		  transita(0);
	        		  contFilas++;
	        	  }
	        	  else if (Eof()){transita(2);}
	        	  else if (sigCar == ' ' || sigCar == '\t' || sigCar == '\r' || sigCar == '\b'){transita(0);}
	              else if(hayLetra()||sigCar=='_'){transita(1);}
	              else if (sigCar == '0'){transita(5);}
	              else if (sigCar >= '1' && sigCar <= '9') {transita(6);}
	              else if (sigCar == ',' ||sigCar == '^' ||sigCar == '.' ||sigCar == ']' ||sigCar == '[' ||sigCar == ';' || sigCar == '@' || sigCar == '(' || sigCar == ')'|| sigCar == '+' || sigCar == '-' || sigCar == '/' || sigCar == '*'
	            	  || sigCar == '%' || sigCar == -1){transita(2);}
	              else if(sigCar == '=' || sigCar == '<' || sigCar == '>' || sigCar == '!'){transita(4);}
	              else if( sigCar == '&'){transita(3);}  
	              else if(sigCar == '|' ){transita(14);} 
	            
	              else {
	                  sigCar = (char) input.read();
	                  System.out.println(sigCar);
	            	  return "ERROR";
	              }
	              break;
	           }
	           case 1:{
	              if (hayLetra() || hayDigito()||sigCar=='_') {transita(1);}
	              else {
	              //Primero vemos si es una palabra reservada.
	                  if (esReservada(lex.toString())){
	                      return "PALRES";}
	                  else {
	                      return "IDEN";}
	              }
	              break;
	           }
	           case 2:{
	        	   if (lex.equals(";")){
	                    return "PUNTOYCOMA";
	               }
	        	   else if (lex.equals(",")){
	                    return "COMA";
	               }
	        	   else if (lex.equals("[")){
	                    return "CORCHETEABIERTO";
	               }
	        	   else if (lex.equals("^")){
	                    return "CIRCUNFLEJO";
	               }
	        	   else if (lex.equals(".")){
	                    return "PUNTO";
	               }
	        	   else if (lex.equals("]")){
	                    return "CORCHETECERRADO";
	               }
	        	   else if (lex.equals("@")){
	                	lex="";
	                	contFilas++;
	                    while (sigCar !='\n'){  //recorrer hasta el final de l�nea
	                        sigCar = (char)input.read();
	                    }
	                    transita(0);
	                    break;
	                }else if (lex.equals("(")){
	                    return "PARABIERTO";
	                }else if (lex.equals(")")){
	                    return "PARCERRADO";
	                }else if (lex.equals("==")){
	                	return "IGUALCOMP";
	                }else if (lex.equals("|")){
	                	if (sigCar=='|')transita(2);
	                }else if (lex.equals("||")){
	                	return "OR";
	                }else if (lex.equals("<=")){
	                	return "MENORIGUAL";
	                }else if (lex.equals(">=")){
	                	return "MAYORRIGUAL";
	                }else if (lex.equals("!=")){
	                	return "DISTINTO";
	                }else if (lex.equals("+")){
	                	return "MAS";
	                }else if (lex.equals("-")){
	                	return "MENOS";
	                }else if (lex.equals("/")){
	                	return "DIV";
	                }else if (lex.equals("*")){
	                	return "MUL";
	                }else if (lex.equals("%")){
	                	return "MOD";
	                }else if (lex.equals("&")){
	                	if(sigCar=='&')transita(2);
	                }else if (lex.equals("&&")){
	                	return "AND";
	                }else if (sigCar == -1){return "EOF";
	                }
	                break;
	             }
	           case 3:{
	        	   if (sigCar=='&')transita(2);
	        	   else return "AMPERSAND";
	        	   break;
	           }
	           case 4:{
	        	   if (sigCar=='=')transita(2);
	        	   else if (lex.equals("=")) return "IGUAL";
	        	   else  if (lex.equals("<"))return "MENOR";
	        	   else  if (lex.equals(">"))return "MAYOR";
	        	   else  if (lex.equals("!"))return "NEGADO";
	        	   else return "ERROR";
	        	   break;
	           }
	           case 5:{
	        	   	if (sigCar=='.')transita(7);
	        	   	else if (sigCar == 'E' || sigCar == 'e')transita(10);
	        	   	else return "NUMCERO";
		               
		       }
	           case 6:{
	               if (hayDigito()){transita(6);}
	               else if(sigCar == '.'){transita(7);}
	               else if(sigCar == 'E' || sigCar == 'e'){transita(10);}
	               else{ return "NUMENTERO";}
	               break;
	           }
	           case 7:{
	        	   if (sigCar >= '1' && sigCar <= '9')transita(8);
	        	   else if (sigCar == '0')transita(9);
	        	   else 
	        		   return "ERROR";
	        	   break;
	           }
	           	
	           case 8:{
	               if (sigCar >= '1' && sigCar <= '9'){transita(8);}
	               else if (sigCar=='0')transita(9);
	               else if(sigCar == 'E' || sigCar == 'e'){transita(10);}
	               else{
	                    return "NUMDECIMAL";
	               }
	               break;
	           }
	           case 9:{
	               
	               if (sigCar=='0'){transita(9);}
	               else if (sigCar >= '1' && sigCar <= '9'){transita(8);}
	               else{
	                    return "ERROR";
	               }
	               break;
	           }
	           case 10:{
	               if ((sigCar >= (int)'1' && sigCar <= (int)'9') ){transita(12);}
	               else if (sigCar=='-'){transita(11);}
	               else if (sigCar=='0'){transita(13);}
	               else{
	                    return "ERROR";
	               }
	               break;
	           }
	           case 11:{
	               if (hayDigito()){transita(12);}
	               else return "ERROR";
	               break;
	           }
	           case 12:{
	               if (hayDigito()){transita(11);}
	               else return "NUMEXPONENCIAL";
	               break;
	           }
	           case 13:{
	        	   if (hayDigito()){ return "ERROR";}
	        	   return "NUMEXPONENCIAL";
	           }
	           case 14:{
	        	   if (sigCar=='|')transita(2);
	        	   else return "ERROR";
	        	   break;
	           }
	          
	         }
	     }

	}
	
	//Para pasar al estado siguiente..
	private void transita(int sig) throws IOException {
	     if (sig>=1){lex = lex + ((char)sigCar);}
	     sigCar = input.read();
	     estado = sig;
	}
	
	public boolean esReservada(String lexema) {
		lex=lex.toLowerCase();
        for (int i=0;i<tablaReservada.length;i++){
            if (lex.equals(tablaReservada[i])){
                return true;
            }
        }
        return false;
    }
	
	private boolean hayDigito() {
	     return sigCar >= '0' && sigCar <= '9';
	}
	
    private boolean Eof(){
        return sigCar == -1;
    }
    
    private boolean hayLetra() {
        return sigCar >= 'a' && sigCar <= 'z' ||
               sigCar >= 'A' && sigCar <= 'Z';
       }
    public String dameLexema(){return lex;}
    
    public int dameContFilas(){
    	return contFilas;
    }

}